home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 028a / sq0928.zip / XUSQ.C < prev   
C/C++ Source or Header  |  1990-09-13  |  9KB  |  420 lines

  1. /*% cc -M2 -compat -O -K -i % -o usq
  2. <-xtx-*> cc -O -K -dos xusq.c /usr/lib/dos/rawmode.o -o usq.exe; ls -l usq.exe
  3.  *
  4.  * usq.c - CP/M compatible file unsqueezer utility
  5.  *   **** N.B.: short int must be 16 bits ****
  6.  */
  7.  
  8. static char *sccsid = "@(#)usq.c        2.17 (CAF) 09-12-90";
  9.  
  10.  
  11. #ifdef vax11c   /*  we only want 16 bit integers  */
  12.  
  13. #include <types.h>
  14. #include <stat.h>
  15. #include <stdio.h>
  16. #include <signal.h>
  17. #include <ctype.h>
  18.  
  19. #else
  20.  
  21. #include <stdio.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <signal.h>
  25. #include <ctype.h>
  26.  
  27. #endif
  28.  
  29.  
  30.  
  31. #define TRUE 1
  32. #define FALSE 0
  33. #define ERROR (-1)
  34. #define PATHLEN    312    /* Number of characters allowed in pathname */
  35. #define OK 0
  36.  
  37. /* Special hacks for BBN C70 with high tech 20 bit integers */
  38. #ifdef C70
  39. #define POSITIVE(i) (i < 0x8000)
  40. #define NEG16TOINT(i) (i |= 0xF000;)
  41. #else
  42. #define POSITIVE(i) (i >= 0)
  43. #define NEG16TOINT(i)
  44. #endif
  45.  
  46. #define SQMAGIC 0xFF76        /* SQueezed file prefix */
  47. #define KSQMAGIC 0xFF75        /* Cipher key magic word */
  48. #define KEYSIZE 4096        /* Max size of key file */
  49.  
  50. unsigned char Keybuf[KEYSIZE];
  51. char Keyname[PATHLEN];
  52. int Key;
  53.  
  54. #define DLE 0x90        /* repeat byte flag */
  55. #define SPEOF 256        /* special endfile token */
  56. #define NUMVALS 257        /* 256 data values plus SPEOF*/
  57. #define LARGE 30000
  58.  
  59.  
  60. struct _sqleaf {        /* Decoding tree */
  61.     short int _children[2];    /* left, right */
  62. };
  63. struct _sqleaf Dnode[NUMVALS - 1];
  64.  
  65.  
  66. int Bpos;        /* last bit position read */
  67. int Repct;        /* Number of times to return value */
  68.  
  69. int MakeLCPathname=TRUE;    /* translate pathname to lc if all caps */
  70. int Nlmode=FALSE;        /* zap cr's if true */
  71. int Fullpathname = FALSE;        /* use full pathname */
  72. int inbackground = 0;
  73. int Verbose = FALSE;
  74. FILE *in, *out;
  75. unsigned char *Keyptr;
  76. unsigned char *Keyend;
  77.  
  78. char *stem();
  79.  
  80. main(argc, argv)
  81. char *argv[];
  82. {
  83.     register char *cp;
  84.     register int npats;
  85.     char **patts;
  86.     int n, errorstat;
  87.  
  88.     if (signal(SIGINT, SIG_IGN)==SIG_IGN)
  89.         inbackground++;
  90.     else
  91.         signal(SIGINT, SIG_DFL);
  92. #ifdef SIGHUP
  93.     signal(SIGHUP, SIG_IGN);
  94. #endif
  95.     npats=0; errorstat=0; out = 0;
  96.     if (argc<2)
  97.         goto usage;
  98.     while (--argc) {
  99.         cp = *++argv;
  100.         if (*cp == '-' && cp[1]) {
  101.             while ( *++cp) {
  102.                 switch(*cp) {
  103.                 case 'f':
  104.                 case 'F':
  105.                     Fullpathname = TRUE; break;
  106.                 case 'l':
  107.                 case 'L':
  108.                     out = stdout; break;
  109.                 case 'n':
  110.                 case 'N':
  111.                     Nlmode=TRUE; break;
  112.                 case 'u':
  113.                 case 'U':
  114.                     MakeLCPathname=FALSE; break;
  115.                 case 'v':
  116.                 case 'V':
  117.                     Verbose=TRUE; break;
  118.                 default:
  119.                     goto usage;
  120.                 }
  121.             }
  122.         }
  123.         else if ( !npats && argc>0) {
  124.             if (argv[0][0]) {
  125.                 npats=argc;
  126.                 patts=argv;
  127.             }
  128.         }
  129.     }
  130.     if (npats < 1) {
  131. usage:
  132.         fprintf(stderr,"%s\n\nUsage: usq [-flnuv] [-] file ...\n",sccsid);
  133.         fprintf(stderr,"\t-f use Full pathname\n");
  134.         fprintf(stderr,"\t-l List file(s) to stdout\n");
  135.         fprintf(stderr,"\t-n Nlmode: remove carriage returns\n");
  136.         fprintf(stderr,"\t-u preserve Uppercase names\n");
  137.         fprintf(stderr,"\t-v Verbose\n");
  138. #ifdef vax11c
  139.         return;
  140. #else
  141.         exit(1);
  142. #endif
  143.     }
  144.     for (n=0; n<npats; ++n)
  145.         errorstat |= usqueeze(patts[n]);
  146. #ifdef vax11c
  147.     return;
  148. #else
  149.     exit(errorstat != 0);
  150. #endif
  151. }
  152.  
  153. /*
  154.  * Following code modified from USQ by Dick Greenlaw.
  155.  */
  156.  
  157. usqueeze(fname)
  158. char *fname;
  159. {
  160.     register int i, c;
  161.     register int numnodes;        /* size of decoding tree */
  162.     register unsigned int crc;
  163.     unsigned filecrc;
  164.     register char *p;
  165.     char origname[PATHLEN];        /* Original file name without drive */
  166.     FILE *kf;
  167.     struct stat st;
  168.     time_t savtim[2];    /* save access & mod times here (sg) */
  169.  
  170.     if (strcmp(fname, "-") == 0)
  171.         in = stdin;
  172.     else if ((in=fopen( fname, "rb"))==NULL) {
  173.         perror(fname);
  174.         return ERROR;
  175.     }
  176.     fstat(fileno(in), &st);            /* Save mod time etc. */
  177.  
  178.     switch (c=portgetw(in)) {        /* Process header */
  179.     case KSQMAGIC:
  180.         Key = TRUE; break;
  181.     case SQMAGIC:
  182.         Key = FALSE; break;
  183.     default:
  184.         fprintf(stderr, "usq: %s is not a SQueezed file MAGIC= %x\n", fname, c);
  185.         fclose(in);
  186.         return(ERROR);
  187.     }
  188.  
  189.     init_cr(); init_huff(); crc=0;
  190.  
  191.     filecrc =  portgetw(in);    /* checksum */
  192.  
  193.     if (Key) {    /* Fetch key file to circular buffer */
  194.         for (i=PATHLEN-1,p=Keyname; --i>0; ) {
  195.             if ((*p++ = getc(in))==0)
  196.                 break;
  197.         }
  198.         if ( !(kf=fopen(Keyname, "r"))) {
  199.             perror(Keyname);
  200.             fclose(in);
  201.             fprintf(stderr, "This key file is required for decryption.\n");
  202.             return ERROR;
  203.         }
  204.         i = fread(Keybuf, 1, KEYSIZE, kf);
  205.         if (i < 100) {
  206.             fclose(in);
  207.             printf("Bad key file or read error");
  208.             return ERROR;
  209.         }
  210.         Keyend = i + (Keyptr = Keybuf);
  211.     }
  212.  
  213.     /* Get original file name to array */
  214.     for (i=PATHLEN,p = origname; --i>0; ) {
  215.         if ((*p++ = c = getc(in)) == 0)
  216.             break;
  217.         if (c == EOF) {
  218.             fprintf(stderr, "usq: premature EOF on %s\n", fname);
  219.             fclose(in); return(ERROR);
  220.         }
  221.     }
  222.  
  223.     numnodes = portgetw(in);
  224.     if (numnodes < 0 || numnodes >= NUMVALS) {
  225.         fprintf(stderr, "usq: %s has invalid decode tree\n", fname);
  226.         fclose(in); return(ERROR);
  227.     }
  228.     /* Initialize for possible empty tree (SPEOF only) */
  229.     Dnode[0]._children[0] = -(SPEOF + 1);
  230.     Dnode[0]._children[1] = -(SPEOF + 1);
  231.  
  232.     for (i = 0; i < numnodes; ++i) {    /* Get decoding tree from file */
  233.         Dnode[i]._children[0] = portgetw(in);
  234.         Dnode[i]._children[1] = portgetw(in);
  235.     }
  236.  
  237.     /* Get translated output bytes and write file */
  238.     if (MakeLCPathname && !IsAnyLower(origname))
  239.         uncaps(origname);
  240.     if (Fullpathname)
  241.         p = origname;
  242.     else
  243.         p = stem(origname);
  244.  
  245.     if (Verbose || !inbackground)
  246.         fprintf(stderr, "usq: %s -> %s\n",fname, p);
  247.     if (out != stdout)
  248.         if ((out=fopen(p, "wb"))==NULL) {
  249.             perror(p);
  250.             fclose(in);
  251.             return ERROR;
  252.         }
  253.     while ((c = getcr()) != SPEOF) {
  254.         crc +=  c;
  255.         if ( c == '\r' && Nlmode)
  256.             continue;
  257.         putc(c, out);
  258.     }
  259.     fflush(out);
  260.     if (out != stdout) {
  261.         fclose(out);
  262. #ifndef vax11c
  263.         savtim[0] = st.st_atime;       /* Access time */
  264.         savtim[1] = st.st_mtime;       /* Modification time */
  265.         utime(p, savtim);
  266. #endif
  267.     }
  268.  
  269.     if (ferror(in))
  270.         perror(fname);
  271.     else if (feof(in))
  272.         fprintf(stderr, "usq: premature EOF in %s\n", fname);
  273.     else if ( (crc - filecrc) & 0xFFFF ) {
  274.         fprintf(stderr, "usq: bad checksum in %s\n", fname);
  275.     } else {
  276.         fclose(in);
  277.         return(OK);
  278.     }
  279.     fclose(in);
  280.     return(ERROR);
  281. }
  282.  
  283. /* initialize decoding functions *** from utr.c - */
  284.  
  285. init_cr()
  286. {
  287.     Repct = 0;
  288. }
  289.  
  290. init_huff()
  291. {
  292.     Bpos = 99;    /* force initial read */
  293. }
  294.  
  295. /*
  296.  * Get bytes with decoding - this decodes repetition,
  297.  * calls getuhuff to decode file stream into byte
  298.  * level code with only repetition encoding.
  299.  *
  300.  * The code is simple passing through of bytes except
  301.  * that DLE is encoded as DLE-zero and other values
  302.  * repeated more than twice are encoded as value-DLE-count.
  303.  */
  304.  
  305. getcr()
  306. {
  307.     register c;
  308.     static value;        /* current byte value or SPEOF */
  309.  
  310.     if (Repct > 0) {
  311.         /* Expanding a repeated char */
  312.         --Repct; return(value);
  313.     } else {
  314.         /* Nothing unusual */
  315.         if ((c = getuhuff()) != DLE) {
  316.             /* It's not the special delimiter */
  317.             if ((value = c) == SPEOF)
  318.                 Repct = LARGE;
  319.             return(value);
  320.         } else {
  321.             /* Special token */
  322.             if ((Repct = getuhuff()) == 0)
  323.                 /* DLE, zero represents DLE */
  324.                 return(DLE);
  325.             else {
  326.                 /* Begin expanding repetition */
  327.                 Repct -= 2;    /* 2nd time */
  328.                 return(value);
  329.             }
  330.         }
  331.     }
  332. }
  333. /* Decode file stream into a byte level code with only
  334.  * repetition encoding remaining.
  335.  */
  336.  
  337. getuhuff()
  338. {
  339.     register i;
  340.     static curin;        /* last byte value read */
  341.  
  342.  
  343.     /* Follow bit stream in tree to a leaf*/
  344.     i = 0;    /* Start at root of tree */
  345.     do {
  346.         if (++Bpos > 7) {
  347.             if ((curin = getc(in)) == EOF)
  348.                 return(SPEOF);
  349.             if (Key) {
  350.                 curin  ^= *Keyptr;
  351.                 if (++Keyptr >= Keyend)
  352.                     Keyptr = Keybuf;
  353.             }
  354.             Bpos = 0;
  355.             /* move a level deeper in tree */
  356.             i = Dnode[i]._children[1 & curin];
  357.         } else
  358.             i = Dnode[i]._children[1 & (curin >>= 1)];
  359.     } while (POSITIVE(i));
  360.     NEG16TOINT(i)
  361.  
  362.     /* Decode fake node index to original data value */
  363.     return (-(i + 1));
  364. }
  365.  
  366. /*
  367.  * Machine independent getw which always gets bytes in the same order
  368.  *  as the CP/M version of SQ wrote them
  369.  */
  370. portgetw(f)
  371. FILE *f;
  372. {
  373.     register c;
  374.  
  375.     c = getc(f) & 0377;
  376.     return(c | ((getc(f)&0377) << 8));
  377. }
  378.  
  379.  
  380. /* make string s lower case */
  381. uncaps(s)
  382. register char *s;
  383. {
  384.     for ( ; *s; ++s)
  385.         if (isupper(*s))
  386.             *s = tolower(*s);
  387. }
  388.  
  389.  
  390. /*
  391.  * IsAnyLower returns TRUE if string s has lower case letters.
  392.  */
  393. IsAnyLower(s)
  394. register char *s;
  395. {
  396.     for ( ; *s; ++s)
  397.         if (islower(*s))
  398.             return(TRUE);
  399.     return(FALSE);
  400. }
  401. /* Return pointer to file name part of pathname s */
  402. char *
  403. stem(s)
  404. char *s;
  405. {
  406.     register char *p;
  407.  
  408.     for (p = s; *s; ) {
  409.         switch (*s++) {
  410.         case ':':
  411.         case '/':
  412.         case '\\':
  413.             p = s;
  414.         }
  415.     }
  416.     return p;
  417. }
  418.  
  419.  
  420.